﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Templates/SubclassOf.h"
#include "UObject/Object.h"
#include "SimpleFactoryPattern.generated.h"

/** 简单工厂模式 Simple Factory Pattern
 *	描述
 *		又称为静态工厂方法，一般使用静态方法，根据参数的不同创建不同类的实例
 *	套路
 *		创建抽象产品类 ；
 *		创建**具体产品类，**继承抽象产品类；
 *		创建工厂类，通过静态方法根据传入不同参数从而创建不同具体产品类的实例；
 *	使用场景
 *		工厂类负责创建的对象比较少：由于创建的对象较少，不会造成工厂方法中的业务逻辑太过复杂。
 *		客户端只知道传入工厂类的参数，对于如何创建对象不关心：客户端既不需要关心创建细节，甚至连类名都不需要记住，只需要知道类型所对应的参数。
 *	优缺点
 *		优点
 *			将创建实例的工作与使用实例的工作分开，实现了解耦；
 *			把初始化实例时的工作放到工厂里进行，使代码更容易维护。
 *		缺点
 *			工厂类集中了所有产品的创建逻辑，一旦这个工厂不能正常工作，整个系统都会受到影响；
 *			违背“开放 - 关闭原则”，添加新产品需要修改工厂类的逻辑
 *			简单工厂模式由于使用了静态工厂方法，静态方法不能被继承和重写，会造成工厂角色无法形成基于继承的等级结构。
 **/

// 抽象类
UCLASS(Abstract)
class MISCELLANEOUSPROJECT_API USimpleFactoryProduct : public UObject
{
	GENERATED_BODY()
public:
	virtual void ShowInfo()
	{
		check(0 && "You must override this");
	}
};

// 具体类A
UCLASS()
class MISCELLANEOUSPROJECT_API USimpleFactoryProductA : public USimpleFactoryProduct
{
	GENERATED_BODY()
public:
	virtual void ShowInfo() override
	{
		// UE_LOG(LogTemp, Warning, TEXT("%s This is a ProductA"), StringCast<TCHAR>(__FUNCTION__).Get());
	}
};

// 具体类B
UCLASS()
class MISCELLANEOUSPROJECT_API USimpleFactoryProductB : public USimpleFactoryProduct
{
	GENERATED_BODY()
public:
	virtual void ShowInfo() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" This is a ProductB"));
	}
};

// 工厂类
UCLASS()
class MISCELLANEOUSPROJECT_API USimpleFactoryFactory : public UObject
{
	GENERATED_BODY()
public:
	static USimpleFactoryProduct* CreateNewProduct(UObject* Outer, TSubclassOf<USimpleFactoryProduct> ProductClass)
	{
		// 此处注意 TSubclassOf 和 NewObject的结合用法
		return NewObject<USimpleFactoryProduct>(Outer, ProductClass);
	}
};

// 调用测试用的Actor
UCLASS()
class MISCELLANEOUSPROJECT_API ASimpleFactoryFactoryActor : public AActor
{
	GENERATED_BODY()
public:
	virtual void BeginPlay() override
	{
		USimpleFactoryProduct* ProductA = USimpleFactoryFactory::CreateNewProduct(
			this, USimpleFactoryProductA::StaticClass());
		ProductA->ShowInfo();

		USimpleFactoryProduct* ProductB = USimpleFactoryFactory::CreateNewProduct(
			this, USimpleFactoryProductB::StaticClass());
		ProductB->ShowInfo();
	}
};
